package filesync;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import net.contentobjects.jnotify.JNotifyException;
import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;

public class FileSync {
    private ArrayList<MonitorSpec> monitorSpecs = new ArrayList<MonitorSpec>();
    private ArrayList<Monitor> monitors = new ArrayList<Monitor>();
    private volatile boolean keepOn = true;

    public FileSync(String[] argv) {
        parseArgs(argv);
        if (monitorSpecs.size() < 1) {
            printHelp();
            System.exit(1);
        }
        dumpArgs();
    }

    private void start() throws IOException {
        for (MonitorSpec m: monitorSpecs) {
            FileCopy.copyFiles(m.getSource(), m.getTarget(), m.getPatterns());
            System.out.println("Initial copying done: " + m.getSource() + " -> " + m.getTarget());
        }

        try {
            Runtime.getRuntime().addShutdownHook(new Thread() {
                public void run() {
                    System.out.println("Control-C caught. Shutting down...");
                    keepOn = false;
                    stopMintoring();
                }
            });

            for (MonitorSpec spec: monitorSpecs)
                monitors.add(new Monitor(spec));
        } catch (InterruptedException e1) {
            e1.printStackTrace();
            System.exit(3);
        }

        while (keepOn) {
            try {
                Thread.sleep(60000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                stopMintoring();
            }
        }
    }

    private void stopMintoring() {
        for (Monitor m: monitors) {
            try {
                System.out.println("Stopping monitoring " + m.getSource() + " -> " + m.getTarget());
                m.stopMonitoring();
            } catch (JNotifyException e) {
                e.printStackTrace();
            }
        }
    }

    private void printHelp() {
        System.out.println("Command line arguments (multiple monitors allowed):");
        System.out.println("  --source=<source dir> or -s <source dir> source dir, per monitor, must be set before target, required");
        System.out.println("  --target=<target dir> or -t <target dir> target dir, per monitor, required");
        System.out.println("  --patterns=<patterns> or -p <patterns>   patterns delimited by |, per monitor, optional");
        System.out.println("  --copy or -c                             global option of making an initial copy, optional");
        //System.out.println(" --file=<conf file name> optional");
        System.out.println("");
        System.out.println("Example:");
        System.out.println("  java -jar filesync -s /src1 -t /tgt1 -p *.jsp|*.js|*.css -s /src2 -t /tgt2");
        System.out.println("");
    }

    private void dumpArgs() {
        for (MonitorSpec m: monitorSpecs) {
            System.out.println("source: " + m.getSource());
            System.out.println("target: " + m.getTarget());
            if (m.getPatterns() != null)
            for (String pattern: m.getPatterns())
                System.out.println("patterns: " + pattern);
        }
    }

    private void parseArgs(String[] argv) {
        File source = null;
        File target = null;
        String[] patterns = null;

        int c;
        StringBuffer sb = new StringBuffer();
        LongOpt[] longopts = new LongOpt[5];
        longopts[0] = new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h');
        longopts[1] = new LongOpt("source", LongOpt.REQUIRED_ARGUMENT, sb, 's'); 
        longopts[2] = new LongOpt("target", LongOpt.REQUIRED_ARGUMENT, sb, 't');
        longopts[3] = new LongOpt("patterns", LongOpt.OPTIONAL_ARGUMENT, sb, 'p');
        longopts[4] = new LongOpt("copy", LongOpt.OPTIONAL_ARGUMENT, sb, 'c');
        //longopts[4] = new LongOpt("level", LongOpt.OPTIONAL_ARGUMENT, sb, 'l');
        //longopts[5] = new LongOpt("delete", LongOpt.OPTIONAL_ARGUMENT, null, 'd');
 
        Getopt g = new Getopt("FileSync", argv, "hs:t:p:l:d", longopts);
        g.setOpterr(false); // We'll do our own error handling

        while ((c = g.getopt()) != -1) {
            if (c == 0)
                c = (new Integer(sb.toString())).intValue();

            switch (c) {
                case 's':
                    if (source != null) {
                        if (target != null) { // end of the last set of params
                            monitorSpecs.add(new MonitorSpec(source, target, patterns));
                            source = null;
                            target = null;
                        } else {
                            System.out.println("Target directory not specified for source " + source);
                            System.exit(2);
                        }
                    }
                    source = new File(g.getOptarg()); 
                    if (!source.exists()) {
                        System.out.println("Source directory does not exist: " + source);
                        System.exit(2);
                    }
                    break;
                case 't':
                    target = new File(g.getOptarg());
                    if (!target.exists()) {
                        System.out.println("Target directory does not exist: " + target);
                        System.exit(2);
                    }
                    break;
                case 'p': patterns = g.getOptarg().split("\\|"); break;
                //case 'l': level = (new Integer(g.getOptarg())).intValue(); break;
                //case 'd': delete = true; break;
                case 'h': printHelp(); break;
             }
        }

        if (source != null)
            if (target != null)
                monitorSpecs.add(new MonitorSpec(source, target, patterns));
            else {
                System.out.println("Target directory not specified for source " + source);
                System.exit(2);
            }
    }

    public static void main(String[] args) throws InterruptedException, IOException {
        FileSync fileSync = new FileSync(args);
        fileSync.start();
    }
}
